#include "AssetManager.hpp"
#include "Audio.hpp"
#include "DeminaAnimation.hpp"
#include "SpriteAnimation.hpp"
#include "Texture.hpp"
#include "TextureDictionary.hpp"
#include "Font.hpp"

namespace fge
{

AssetManager::AssetManager(const std::string &assetPath)
	: assetPath(assetPath)
{
}

template <typename T>
void DeleteMapContents(std::map<std::string, T> &map)
{
	typename std::map<std::string, T>::iterator iterator = map.begin();
	typename std::map<std::string, T>::iterator end = map.end();

	while(iterator != end)
	{
		delete iterator->second;
		++iterator;
	}
}

AssetManager::~AssetManager()
{
	// the texture dictionary loader pushes "DictionaryName.td" into the textures list
	// as a way to easily look up a dictionary
	// but it's just a copy, and we don't want to delete it, so just clear it out first
	std::map<std::string, Texture*>::iterator iterator = textures.begin();
	while(iterator != textures.end())
	{
		if(iterator->first.find(".td") != iterator->first.npos)
			textures.erase(iterator++);
		else
			++iterator;
	}

	DeleteMapContents(textures);
	DeleteMapContents(textureDictionaries);
	DeleteMapContents(deminaAnimations);
	DeleteMapContents(spriteAnimations);
	DeleteMapContents(songs);
	DeleteMapContents(soundEffects);
	DeleteMapContents(fonts);
}

std::pair<Texture*, TextureRegion> AssetManager::LoadTextureWithRegion(const std::string &fileName)
{
	std::pair<Texture*, TextureRegion> data;
	data.first = LoadTexture(fileName, &data.second);
	return data;
}

Texture* AssetManager::LoadTexture(const std::string &fileName, TextureRegion *region)
{
	if(region != NULL)
	{
		std::map<std::string, TextureDictionary*>::iterator end = textureDictionaries.end();
		for(std::map<std::string, TextureDictionary*>::iterator iterator = textureDictionaries.begin();
			iterator != end; ++iterator)
		{
			if(iterator->second->ContainsTexture(fileName))
			{
				*region = iterator->second->GetRegion(fileName);
				return textures[iterator->first];
			}
		}
	}

	std::map<std::string, Texture*>::iterator iter = textures.find(fileName);
	if (iter != textures.end())
	{
		if(region != NULL)
		{
			region->rect.x = region->rect.y = 0;
			region->origin = fge::Vector2(0.5f, 0.5f);
			region->rect.w = iter->second->GetWidth();
			region->rect.h = iter->second->GetHeight();
		}
		return iter->second;
	}
	else
	{
		Texture *texture = Texture::FromFile(assetPath + fileName);
		if(texture == NULL)
			return NULL;
		if(region != NULL)
		{
			region->rect.x = region->rect.y = 0;
			region->origin = fge::Vector2(0.5f, 0.5f);
			region->rect.w = texture->GetWidth();
			region->rect.h = texture->GetHeight();
		}
		textures[fileName] = texture;
		return texture;
	}
}

TextureDictionary* AssetManager::LoadTextureDictionary(const std::string &dictionaryFile, const std::string &imageFile)
{
	std::map<std::string, TextureDictionary*>::iterator iter = textureDictionaries.find(dictionaryFile);
	if (iter != textureDictionaries.end())
	{
		return iter->second;
	}
	else
	{
		TextureDictionary *textureDictionary = TextureDictionary::FromFile(assetPath + dictionaryFile);
		if(textureDictionary == NULL)
			return NULL;
		textureDictionaries[dictionaryFile] = textureDictionary;

		Texture *texture = LoadTexture(imageFile);
		if(texture == NULL)
			return NULL;
		textures[dictionaryFile] = texture;

		return textureDictionary;
	}
}

DeminaAnimation* AssetManager::LoadDeminaAnimation(const std::string &fileName)
{
	std::map<std::string, DeminaAnimation*>::iterator iter = deminaAnimations.find(fileName);
	if (iter != deminaAnimations.end())
	{
		return iter->second;
	}
	else
	{
		DeminaAnimation *deminaAnimation = new DeminaAnimation(fileName, this);
		deminaAnimations[fileName] = deminaAnimation;
		return deminaAnimation;
	}
}

SpriteAnimation* AssetManager::LoadSpriteAnimation(const std::string &fileName)
{
	std::map<std::string, SpriteAnimation*>::iterator iter = spriteAnimations.find(fileName);
	if (iter != spriteAnimations.end())
	{
		return iter->second;
	}
	else
	{
		SpriteAnimation *spriteAnimation = new SpriteAnimation(fileName, this);
		spriteAnimations[fileName] = spriteAnimation;
		return spriteAnimation;
	}
}

Song* AssetManager::LoadSong(const std::string &fileName)
{
	std::map<std::string, Song*>::iterator iter = songs.find(fileName);
	if (iter != songs.end())
	{
		return iter->second;
	}
	else
	{
		Song *song = Song::FromFile(assetPath + fileName);
		if(song == NULL)
			return NULL;
		songs[fileName] = song;
		return song;
	}
}

SoundEffect* AssetManager::LoadSoundEffect(const std::string &fileName)
{
	std::map<std::string, SoundEffect*>::iterator iter = soundEffects.find(fileName);
	if (iter != soundEffects.end())
	{
		return iter->second;
	}
	else
	{
		SoundEffect *soundEffect = SoundEffect::FromFile(assetPath + fileName);
		if(soundEffect == NULL)
			return NULL;
		soundEffects[fileName] = soundEffect;
		return soundEffect;
	}
}

Font* AssetManager::LoadFont(const std::string &fileName)
{
	std::map<std::string, Font*>::iterator iter = fonts.find(fileName);
	if (iter != fonts.end())
	{
		return iter->second;
	}
	else
	{
		Font *font = Font::FromFile(assetPath + fileName);
		if(font == NULL)
			return NULL;
		fonts[fileName] = font;
		return font;
	}
}
	
}
